import re
import numpy as np
import copy
from multiprocessing import Process
import logging
import json
from ctypes import *


Timestamp = "Timestamp" #

def comment():
    """
    dbc_net_dict = {

        'name': 'can0',
        'rate': 500000,
        'byte_order': 'indel',
        'node_list': 'esc icu mcu',
        'ecu_list': [
            {   'name': 'ecu0',
                'frame_list':
                    [
                    {
                        'name': 'frame_name1',
                        'id' : id,
                        'data_len': 8,
                        'send_type': 0#"Cycle","NoSendType","IfActive"
                        'sig_list': [
                          {
                            'name': row_str[Name_col_index],
                            'sig_description': '',
                            'bit_info': [int(row_str[Sig_bit_start_col_index]), int(row_str[Sig_bit_len_col_index])],
                            'cal_info': [1, 0],
                            'min_max': [0, 1],
                            'unit': row_str[Unit_col_index],
                            'value_description': row_str[Value_description_col_index],
                            'value_table': ['a', 'b'],
                            'init_value': row_str[Ini_col_index],
                            'recive_ecu': self.GetReceviEcuList([row_str[i] for i in range(13, 25)], node_list),
                            'send_ecu': self.GetSendEcu([row_str[i] for i in range(13, 25)], node_list),
                            'value': 0}  # value_description " value_tabler 或其他值
                            }
                            'cycle': int
                        ]
                    },
                    ]
            }
        ]
    }
    """
    # comment<<


folat_str_reg = "\-?\d+\.?\d*E?\+?\d*"

# 获得信号的值
# dbc_op=DbcClass(dbc_name)
# data = [0, 1, 2, 3, 4, 5 , 114, 255]
# dbc_op.ACU_3A0.ACU_RollingCounter.CalValByData8(data)

class BaseData:
    '''
    对时间序列数据进行通用操作
        设定数据长度
        清空数据
        添加数据（时间和数据分开添加， 其中时间数据可以为[]）
    '''
    Max_data_len = 1000
    Data = []  
    Timestamp = []
    def SetMaxDataLen(self,max_len):
        """
        最小长度是100
        """
        self.Max_data_len = max_len if max_len>100 else 100
        now_len = len(self.Data)
        if(now_len > self.Max_data_len):
            self.Data = self.Data[now_len-self.Max_data_len:]

        now_len = len(self.Timestamp)
        if(now_len > self.Max_data_len):
            self.Timestamp = self.Timestamp[now_len-self.Max_data_len:]
        pass
    def AddData(self,new_data,timestamp = []):
        '''
        插入新的数据
        通过将参数放入list 达到取地址的目的
        '''
        self.SetMaxDataLen(self.Max_data_len-len(new_data))#删除数据
        self.Data.extend(new_data)
        if(timestamp):
            self.SetMaxDataLen(self.Max_data_len-len(timestamp))#删除数据
            self.Timestamp.extend(timestamp)
    def ClearData(self):
        self.Data = []
        self.Timestamp = []
    def GetVal(self,index=None):
        '''
        获取Data的最后一个数据
        如果Data为空，则返回0 
        >>> from dbc import BaseData
        >>> base_class = BaseData()
        >>> base_class.Data = [1,2,3]
        >>> print(base_class.GetVal())
        3
        >>> base_class.Data = []
        >>> print(base_class.GetVal())
        0
        ''' 
        res = self.Data[-1] if self.Data else 0
        return res

class SigClass(BaseData):
    '''
    Timestamp 信息继承Frame的同一地址值
    '''
    # 确定信号处理的类

    data_array = [None, None, None, None, None, None, None, None]#上一次处理的 data8
    # Data = []  # 所有时间段中的信号数据, 默认值为0
    # Max_data_len = 1000
    res = None
    err_count = 0  # 信号出错计数
    ID= 0
    full_name = "ecu_id.sig_name"
    frame = None  # 父级frame 类句柄
    name = ""
    cal_info=[]
    bit_info=[]
    enum_value_list = []
    def __init__(self, sig,max_data_len = 1000):
        self.sig = sig
        self.name = sig["name"]
        self.err_count = 0
        self.data_array = []
        self.cal_info = sig["cal_info"]
        self.bit_info = sig["bit_info"]
        self.enum_value_list =[] 
        self.ClearData()
        self.SetMaxDataLen(max_data_len)
        pass

    def __call__(self):
        print("dbc call")
        pass

        # def val(self, t=[]):
        # TODO 获取所需要的值， 未完成
        """
        if ((type(t) == "float") or
            (type(t) == "float")):  # 获取 t时刻
            pass
        else:
            if(t == []):  # 获取所有的值
                pass
            elif(t[0] == t[1]):  # 获取 t时刻的值
                pass
            else:  # 获取 t[0] t[1]时刻之间的值
                pass
            pass
        """

    def GetVaueTableStrByVal(self,val):
        '''
        依据值获取对应的枚举值
        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> sig_class = dbc_class.EPS_280.SAS_CalibrationSts
        >>> print(sig_class.enum_value_list)
        ['Sensor_not_calibrated', 'Sensor_calibrated']
        >>> val = sig_class.GetVaueTableStrByVal(1.0)
        >>> print(val) 
        Sensor_calibrated
        >>> sig_class = dbc_class.EPS_280.SAS_SteerWheelRotSpd
        >>> val = sig_class.GetVaueTableStrByVal(1.0)
        >>> print(val) 
        1.0

        '''
        res_str = ''
        if (self.enum_value_list
            and (len(self.enum_value_list) > 0) 
            and (len(self.enum_value_list) > val) 
            and (val > 0)):
            res_str = self.enum_value_list[int(val)]
        else:
            res_str=str(val)
        return res_str

    def CalValByData8(self, data8 = []):
        '''
        # 检查整个报文有没变化,计算data8对应的值
        # 如果传入的data8 为空， 则取Data中的值

        # TODO del
        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> sig_class = dbc_class.EPS_280.SAS_CalibrationSts
        >>> val = sig_class.CalValByData8([255]*8)
        >>> print(val)
        1.0
        >>> val = sig_class.CalValByData8([255]*8)
        >>> print(val)
        1.0
        '''
        if(not data8):
            tmp_res = self.G
            return 

        if (self.data_array == data8):#PY3.8以后可以正常使用
            res = self.res
            logging.debug("数据没有更新")
        else:
            bit_info = self.sig["bit_info"]
            cal_info = self.sig["cal_info"]
            res = self.Cal_BitData(data8, bit_info, cal_info)
            self.res = res
        return res 
        #<<end CalValByData8

    def GetValByIndex(self, index):
        return self.Data[index]

    def SetMaxDataLen(self,max_len):
        """
        最小长度是100
        """
        self.Max_data_len = max_len if max_len>100 else 100

        now_len = len(self.Data)
        if(now_len > self.Max_data_len):
            self.Data = self.Data[now_len-self.Max_data_len:]
            # self.Timestamp = self.Timestamp[now_len-self.Max_data_len:]
        pass

    def UpdateData(self, data8_array, timestamp_array=[]):
        '''
            2021-07-25 23:55:01
            更新信号的数值
            data8_array:
                修改传入的参数为list [[1,2,3,4,5,6,7,8], [1,2,3,4,5,6,7,8]]
            时间参数，暂时未用
        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> sig_class = dbc_class.EPS_280.SAS_CalibrationSts
        >>> val = sig_class.CalValByData8([1,2,3,4,5,6,7,8])
        >>> print(val)
        0.0
        >>> val = sig_class.CalValByData8([255]*8)
        >>> print(val)
        1.0
        >>> sig_class.UpdateData([[1,2,3,4,5,6,7,8]])
        >>> sig_class.UpdateData([[255]*8])
        >>> print(sig_class.Data)
        [0.0, 1.0]

        '''

        self.SetMaxDataLen(self.Max_data_len-len(data8_array))#删除数据
        self.Data.extend( [self.CalValByData8(data8) for data8 in (data8_array) ])

    def Cal_BitData(self, data8, bit_info, cal_info):
        '''
        依据输入的数据计算信号值
            先判断对应的数位信息有没有变， 没有变化则取上一次的值即可

        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> sig_class = dbc_class.EPS_280.SAS_CalibrationSts
        >>> res = sig_class.Cal_BitData([0]*8, bit_info = sig_class.bit_info, cal_info = sig_class.cal_info);
        >>> print(res)
        0.0
        >>> res = sig_class.Cal_BitData([255]*8, bit_info = sig_class.bit_info, cal_info = sig_class.cal_info)
        >>> print(res)
        1.0
        '''
        new_data = []
        # 检查起始位越过几个字节
        start_byte = int(bit_info[0] // 8)
        start_bit = int(bit_info[0] % 8)
        bit_len = bit_info[1]
        # 检查 信号对应位是否发生变化
        no_change = ( data8[start_byte : (start_byte + 1)] == self.data_array[start_byte : (start_byte + 1)]) 
        if no_change:
            res = self.res
        else:
            if bit_len > 8:
                val = int((0x100 * data8[start_byte + 1] + data8[start_byte]))
            else:
                val = int(data8[start_byte])
                pass
            # 最长信号位 32 位，  字节反序计算 固定（leap 格式， 高位在前）

            bit_and = 0x0000
            for tmp in range(bit_len):
                bit_and = (bit_and << 1) + 1

            tmp_res = (val >> start_bit) & bit_and
            res = tmp_res * cal_info[0] + cal_info[1]
            self.res = res
        return res


class FrameClass(BaseData):
    # 确定帧处理的类
    # 实际使用的时候需要修改长度1 为真实长度
    # Data = []#
    # Timestamp = []
    cycle = (0,)
    # sig_list = []  # 在frame 中已经包含了
    # frame = None

    def __init__(self, frame, max_data_len = 1000):
        # self.frame = frame
        Max_data_len = 1000
        self.cycle = frame["cycle"]
        self.id = frame["id"]
        self.name = frame["name"]
        self.send_ecu = frame["send_ecu"]
        self.sig_list = frame["sig_list"]

        self.Recive_ecu_list = []  # 从ECU判断要检查哪些信号
        # 检查frame 格式
        self.CheckFramePara(frame)
        self.ClearData()
        self.SetMaxDataLen(max_data_len)
        for sig in frame["sig_list"]:
            sig_class = SigClass(sig, max_data_len=self.Max_data_len)

            # sig_class = SigClass(sig, self.Timestamp)
            setattr(self, sig["name"], sig_class)
            setattr(sig_class, "Timestamp", self.Timestamp)  # 时间应用帧的时间戳
            setattr(sig_class, "ID", self.id)  
            setattr(sig_class, "frame", self)  # sigclass 记录父级frame的信息
            setattr( sig_class, "full_name", frame["name"] + "." + sig["name"])  # sigclass 记录父级frame的信息
            setattr( sig_class, "enum_value_list", sig["value_table"]["enum_value_list"])  # sigclass 枚举值查找标
        pass

    def __inster_data_by_time__(self, timestamp_array, data8_array):
        # 插入新的数据到frame， 并给出插入的index用于更新sig
        pass

    def GetTPos(self, t, gate):
        '''
        # gate = [前取时间, 后取时间]
        # 截取时间点前后t_gaet 的 tpos
        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> frame_class = dbc_class.EPS_280
        >>> frame_class.Timestamp = list(np.arange(0,3,0.1))
        >>> res = frame_class.GetTPos(2,[-0.2,0.2])
        >>> print(res)
        (array([22], dtype=int64),)

        '''
        np_time = np.array(self.Timestamp)
        pos = np.where(
            (
                (np_time >= (t - gate[0]))
                & (np_time <= (t + gate[1]))
            )
        )

        #  # TODO 估算出时间范围再用npwhere 查找
        """
        # timestamp = self.Timestamp[0]

        # pos0 = max(
                # int((t - timestamp[0] - gate[0])*1000 / self.cycle) -1,
                # 0)
        # pos1 = min(
                # len(timestamp) ,
                # int((t - timestamp[0] + gate[1])*1000 / self.cycle) + 1
                # )
        # pos = list((range(pos0, pos1)))
        """
        return pos

    def CheckFramePara(self, frame):
        """ 检查帧是否合格 """
        pass

    def GetTimeStamp(self):
        # 获取fram数据的时间属性
        pass

    def GetDataByTime(self, time_array):
        pass

    def SetTimeData(self, Timestamp_array):
        pass

    def GetCycle(self):
        pass

    def SetMaxDataLen(self,max_len):
        """
        最小长度是100
        """
        self.Max_data_len = max_len if max_len>100 else 100

        now_len = len(self.Data)
        if(now_len > self.Max_data_len):
            self.Data = self.Data[now_len-self.Max_data_len:]
            self.Timestamp = self.Timestamp[now_len-self.Max_data_len:]
        pass
    def UpdateSigData(self,frame_array):
        '''
            更新每个信号的值
            此处的frame ID必须和本frame 的iD一致, 软件不再做校验
        >>> from dbc import Py_Dbc
        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> frame1 = {"ID":0x280,"Timestamp":1,"Data":[5]*8}
        >>> frame2 = {"ID":0x280,"Timestamp":2,"Data":[255]*8}
        >>> frame_array = [frame1,frame2]
        >>> dbc_class.EPS_280.UpdateSigData(frame_array)
        >>> print(dbc_class.EPS_280.Timestamp)
        [1, 2]
        >>> data = dbc_class.EPS_280.SAS_CalibrationSts.Data[-1]
        >>> print(data)
        1.0
        >>> data = dbc_class.EPS_280.SAS_SteerWheelRotSpd.Data[-1]
        >>> print(data)
        1020.0
        >>> dbc_class.EPS_280.UpdateSigData(frame_array)
        >>> print(dbc_class.EPS_280.Timestamp)
        [1, 2, 1, 2]

        '''
        #检查数据长度
        self.SetMaxDataLen(self.Max_data_len-len(frame_array))#删除数据
        self.Timestamp.extend([frame["Timestamp"] for frame in frame_array])
        self.Data.extend([frame["Data"] for frame in frame_array])

        for sig in self.sig_list:
            sig_class = getattr(self, sig["name"])
            sig_class.UpdateData(data8_array = [frame["Data"] for frame in frame_array])
            """
            # np 的索引会出问题 ， 二维数组会变一维。。。。原因不知道
            # tmp_data = []
            # [tmp_data.append(
                # sig_class.CalValByData8(self.Data[..., i])) for i in range(data_shape[1])]
            # sig_class.Data = np.array(tmp_data)
            """
            pass  # for
        pass  # UpdateSigData

    pass

class PrcPariseFrameDataByDbc(Process):
    """
    按照dbc解析信号值, 从队列读取报文数据, 解析后的数据从quee中传出
    @args
        "dbc": dbc,
        "frame_quee": frame_quee,
        "frame_with_sig_data_quee": frame_with_sig_data_quee,
    @作者 2020.12.29 gcbb
    """

    def __init__(self, args):
        super().__init__()
        self.args = args
        self.Dbc = self.args["dbc"]
        pass

    def run(self):
        self.args["frame_with_sig_data_quee"].put("测试生效")
        args = self.args
        dbc = self.Dbc
        frame_with_sig_data_quee = self.args["frame_with_sig_data_quee"]
        frame_quee = self.args["frame_quee"]

        while True:
            frame_data = frame_quee.get()
            frame_class = dbc.UpdateFrameData(frame_data)
            frame_with_sig_data_quee.put(frame_class)
            pass


class Py_Dbc(Process, BaseData):
    '''
    >>> dbc_class = Py_Dbc("dbc/C11.dbc")
    
    '''
    dbc_net = {}
    frame_list = []
    reg_cm_sg = "CM_ SG_ "
    reg_id = "(\S+)"
    reg_sig_name = "(\S+)"
    reg_comment = '"(.+)";$'
    Dbc_file_enc = "gbk"
    # Max_data_len = 1000# frame 和signal 的存储数据长

    def __init__(self, dbc_file = None, max_data_len = 1000):

        self.dbc_net = {}
        self.frame_list = []
        if(dbc_file):
            self.load_dbc(dbc_file)
        pass

    def load_dbc(self, dbc_file):

        logging.info("加载DBC文件")
        tmp_text = ''
        try:
            with   open(dbc_file, encoding="utf-8") as tmp_file:
                tmp_text = tmp_file.read()
                self.Dbc_file_enc ="utf-8"
        except Exception:
            with   open(dbc_file, encoding="gbk") as tmp_file:
                tmp_text = tmp_file.read()
            tmp_file.close()
            self.Dbc_file_enc = "gbk"
        dbc_net = self.Parise_DbcStr(tmp_text)
        self.dbc_net = dbc_net
        self.UpdateFrameList()
        self.CreateFrameClass(self.GetFrameList())

        return

    def CreateFrameClass(self, frame_list):
        # 创建每个ID的类
        # dbc_op.ACU_3A0.ACU_RollingCounter.CalValByData8(data)
        for frame in frame_list:
            tmp_hdl = FrameClass(frame, max_data_len=self.Max_data_len)
            setattr(self, frame["name"], tmp_hdl)
            pass

    # 解析DBC 存储到列表中
    def StartPrcPariseFrameDataByDbc(
        self, dbc, dbc_path, frame_quee, frame_with_sig_data_quee
    ):

        """
        启动进程，解析DBC的值

            "dbc": dbc,
            "frame_quee": frame_quee,
            "frame_with_sig_data_quee": frame_with_sig_data_quee,
        """

        p_list = []
        print("格式化ASC文件信息(行)，请稍等")
        args = {
            "dbc_path": dbc_path,
            "dbc": self,
            "frame_quee": frame_quee,
            "frame_with_sig_data_quee": frame_with_sig_data_quee,
        }
        p = PrcPariseFrameDataByDbc(args)
        p.start()
        return p

    # 入口函数，解析DBC为dbc_net
    def Parise_DbcStr(self, dbc_text):
        tmp_text_array = dbc_text.split("\n")
        ecu_list = []

        net_name = self.Pares_NetName(dbc_text)
        node_list = self.Pares_NodeList(dbc_text)
        dbc_net = {
            "name": net_name,
            "rate": 500,
            "byte_order": "intel",
            "node_list": node_list,
            "ecu_list": ecu_list,
        }

        new_frame = None
        for tmp_text in tmp_text_array:

            tmp_frame = self.Parise_Bo(tmp_text, ecu_list)
            if tmp_frame is not None:
                new_frame = tmp_frame
                continue
            # 这一条TXT 是否为报文定义
            if new_frame is not None:
                # 没有查找到BO直接跳过SIG

                tmp_sig = self.Parise_Sig(tmp_text)
                if tmp_sig is not None:
                    new_frame["sig_list"].append(tmp_sig)
                    continue
                    pass

            # 这一条TXT 是否为枚举定义
            value_table = self.Parise_EnumDef(tmp_text, dbc_net)
            if value_table is not None:
                continue

            # 这一条TXT 是否为周期定义
            if self.Parise_CycInfo(tmp_text, ecu_list) is not None:
                continue

            sig_description = self.PariseSigDiscription(tmp_text)
            if sig_description:
                self.UpdateDbcNetSigDiscription(sig_description, dbc_net)

        # 这一条txt 是否是网络名定义
        # 排序
        dbc_net = self.SortDbcNet(dbc_net)
        return dbc_net

    # 解析BO
    # 如果有新的SendECU 则新增ECUlist
    # 如果已经存在ECU 则插入Framee 到ecu_list["frame_list"]中

    def Parise_Bo(self, text, ecu_list):
        # BO_ 591 EPS_24F: 8 EPS
        tmp_match_str = r"^BO_ (" + folat_str_reg + ") (\S+): (\d) (\S+)$"
        tmp_match_res = re.match(tmp_match_str, text)
        frame = None
        if tmp_match_res is not None:
            # tmp_len = len(tmp_match_res.group())
            frame = {
                "id": int(tmp_match_res.group(1)),
                "name": tmp_match_res.group(2),
                "data_len": tmp_match_res.group(3),
                "send_type": 0,
                "send_ecu": tmp_match_res.group(4),
                "recive_ecu": [],  # 为所有信号的接收合集
                "cycle": int(0),
                "sig_list": [],
            }

            # 如果已经存在ECU 则插入Framee 到ecu_list["frame_list"]中
            # 如果有新的SendECU 则新增ECUlist
            new_ecu_flag = 1
            for ecu in ecu_list:
                if ecu["name"] == frame["send_ecu"]:
                    ecu["frame_list"].append(frame)
                    new_ecu_flag = 0
            if new_ecu_flag:
                new_ecu = {"name": frame["send_ecu"], "frame_list": [frame]}
                ecu_list.append(new_ecu)
        return frame

    def Parise_Sig(self, text):

        """
        import ipdb as pdb
        pdb.set_trace()
            解析文本行，
            返回新的信号列表
        """
        # SG_ EPS_ColumnTorque : 0|16@1+ (0.01, -200) [-200|200] "Nm" Vector__XXX
        # folat_str_reg = '\-?\d+\.?\d*'
        new_sig = None

        sg_str = (
            r"^ +SG_\s+"  # sg标识
            + "(\S+)\s+: "  # 信号名
            + "(\d+)\|(\d+)@\d[\+-] "  # 位信息，大小端
            + "\(("
            + folat_str_reg
            + "),("
            + folat_str_reg
            + ")\) "
            + "\[("
            + folat_str_reg  # 位计算信息
            + ")\|("
            + folat_str_reg  # 单位
            + ")\]\s+(\S*)\s+(\S*)\s*"  # 接收ECU
        )
        tmp_match_res = re.match(sg_str, text)

        if tmp_match_res is not None:
            recive_ecu = tmp_match_res.group(9).split(",")  # 接收列表
            new_sig = {
                "name": tmp_match_res.group(1),
                "bit_info": [int(tmp_match_res.group(2)), int(tmp_match_res.group(3))],
                "cal_info": [
                    float(tmp_match_res.group(4)),
                    float(tmp_match_res.group(5)),
                ],
                "unit": tmp_match_res.group(8)[1:-1],  # 需要处理掉两侧的 ""
                "min_max": [
                    float(tmp_match_res.group(6)),
                    float(tmp_match_res.group(7)),
                ],  # TODO 最大最小值
                "recive_ecu": recive_ecu,
                "value": float(0),
                "value_table": {"table_name": "none", "enum_value_list": None},
                "sig_description": "",  # 后面会由UpdateDbcNetSigDiscription更新
            }
            # new_sig_list.append(new_sig)
        return new_sig

    def Parise_EnumDef(self, text_line, dbc_net):
        """
        读取dbc 的字符串
        如果时枚举定义类型，则将枚举类型添加到信号值对应的value_table中
        """
        value_table = None
        flag = None
        rg_str = r"^VAL_ \d+ (\S+) (.+)$"
        tmp_match_res = re.match(rg_str, text_line)
        if tmp_match_res is not None:
            value_table = []

            tmp_val_table_name = tmp_match_res.group(1)

            tmp_table_str = tmp_match_res.group(2)
            rg_str = r'"\s*([a-zA-Z0-9 _]+)\s*"'
            value_table = re.findall(rg_str, tmp_table_str)

            # 对重复定义重命名  xx->xx1
            i = 0
            for tmp_val in value_table:
                # 替换空格为下划线
                tmp_val = tmp_val.replace(u" ", u"_")

                count = value_table.count(tmp_val)
                if count > 1:
                    tmp_val = tmp_val + str(count - 1)

                value_table[i] = tmp_val
                i += 1

            value_table.reverse()

            # 添加到对应sig 的valu_table中
            for ecu in dbc_net["ecu_list"]:
                for frame in ecu["frame_list"]:
                    for sig in frame["sig_list"]:
                        if sig["name"] == tmp_val_table_name:
                            sig["value_table"] = {
                                "table_name": tmp_val_table_name,
                                "enum_value_list": value_table,
                            }
                            return
        return value_table

    # 解析dbc 获取网络名
    # 如果未定义则设置为 undef
    def Pares_NetName(self, dbc_str):
        flag = None
        rg_str = r'BA_ "DBName" "(\S+)"'
        tmp_match_res = re.search(rg_str, dbc_str)
        net_name = "undef"
        if tmp_match_res is not None:
            net_name = tmp_match_res.group(1)
        return net_name

    # 解析dbc 获取列表
    def Pares_NodeList(self, dbc_str):
        flag = None

        # BU_:  VCU MCU BCM ICU MMI ESC EPS
        rg_str = r"BU_:(.+)\n"
        tmp_match_res = re.search(rg_str, dbc_str)
        node_list = []
        if tmp_match_res is not None:
            node_list_str = tmp_match_res.group(1)
            node_list = node_list_str.split()
        node_list = sorted(node_list)
        return node_list
        pass  # Pares_NodeList<<

    # 解析对应报文的周期 和发送类型
    def Parise_CycInfo(self, text, ecu_list):
        # BA_ "GenMsgCycleTime" BO_ 256 20;
        # folat_str_reg = '\-?\d+\.?\d*'
        flag = None
        rg_str = r'^BA_ "(GenMsgSendType|GenMsgCycleTime)"\s+BO_\s+(\d+)\s+(\d+);\s*$'
        TYPE_INDEX = 1
        ID_INDEX = 2
        SEND_TYPE_OR_CYCLE_INDEX = 3
        tmp_match_res = re.match(rg_str, text)

        if tmp_match_res is None:
            return flag
        else:
            flag = 1
            cyc_id = int(tmp_match_res.group(ID_INDEX))
            cyc_time_or_type = int(tmp_match_res.group(SEND_TYPE_OR_CYCLE_INDEX))
            for ecu in ecu_list:
                for frame in ecu["frame_list"]:
                    if frame["id"] == cyc_id:
                        if tmp_match_res[TYPE_INDEX] == "GenMsgSendType":
                            frame["send_type"] = cyc_time_or_type
                        else:
                            frame["cycle"] = cyc_time_or_type
            pass
        return flag

    def PariseSigDiscription(self, text):
        """
        解析信号说明，并更新填入dbc_net
        """

        sig_description = None
        rg_str = (
            self.reg_cm_sg
            + self.reg_id
            + " "
            + self.reg_sig_name
            + " "
            + self.reg_comment
        )
        tmp_match_res = re.match(rg_str, text)
        if tmp_match_res:
            sig_description = {
                "id": int(tmp_match_res[1]),
                "sig_name": tmp_match_res[2],
                "comment": tmp_match_res[3],
            }
        return sig_description  # PariseSigDiscription<<

    def UpdateDbcNetSigDiscription(self, sig_description, dbc_net):
        """
        更新信号说明到dbc中
        >>> import logging
        >>> logging.basicConfig(level=100)
        >>> from dbc import Py_Dbc
        >>> dbc_class = Py_Dbc("dbc/C11.dbc")
        >>> sig_description = { "id": 869, "sig_name": "LKA_WarningType", "comment": "LKA\u538b\u7ebf\u544a\u8b66\u4fe1\u53f7" }
        >>> dbc_net = {\
                "ecu_list":[\
                    {\
                        "name": "EPS",\
                        "frame_list": [\
                            {\
                                "id": 896,\
                                "name": "EPS_380",\
                                "data_len": "8",\
                                "send_type": 0,\
                                "send_ecu": "EPS",\
                                "recive_ecu": [],\
                                "cycle": 0,\
                                "sig_list": [\
                                    {\
                                        "name": "EPS_CheckSum",\
                                        "bit_info": [\
                                            56,\
                                            8\
                                        ],\
                                        "cal_info": [\
                                            1.0,\
                                            0.0\
                                        ],\
                                        "unit": "",\
                                        "min_max": [\
                                            0.0,\
                                            255.0\
                                        ],\
                                        "recive_ecu": [\
                                            "Vector__XXX"\
                                        ],\
                                        "value": 0.0,\
                                        "value_table": {\
                                            "table_name": "none",\
                                            "enum_value_list": []\
                                        },\
                                        "sig_description": ""\
                                    },\
                                    {\
                                        "name": "EPS_RollingCounter",\
                                        "bit_info": [\
                                            52,\
                                            4\
                                        ],\
                                        "cal_info": [\
                                            1.0,\
                                            0.0\
                                        ],\
                                        "unit": "",\
                                        "min_max": [\
                                            0.0,\
                                            15.0\
                                        ],\
                                        "recive_ecu": [\
                                            "Vector__XXX"\
                                        ],\
                                        "value": 0.0,\
                                        "value_table": {\
                                            "table_name": "none",\
                                            "enum_value_list": []\
                                        },\
                                        "sig_description": ""\
                                    },\
                                    {\
                                        "name": "EPS_ColumnTorque",\
                                        "bit_info": [\
                                            0,\
                                            16\
                                        ],\
                                        "cal_info": [\
                                            0.01,\
                                            -200.0\
                                        ],\
                                        "unit": "Nm",\
                                        "min_max": [\
                                            -200.0,\
                                            200.0\
                                        ],\
                                        "recive_ecu": [\
                                            "Vector__XXX"\
                                        ],\
                                        "value": 0.0,\
                                        "value_table": {\
                                            "table_name": "none",\
                                            "enum_value_list": []\
                                        },\
                                        "sig_description": ""\
                                    }\
                                ]\
                            }\
                        ]\
                    }\
                ]\
        }
        >>> dbc_class.UpdateDbcNetSigDiscription(sig_description,dbc_net)
        {'id': 869, 'sig_name': 'LKA_WarningType', 'comment': 'LKA压线告警信号'}不存在与DBC NET中， 找不到对应的ID

        >>> sig_description = { "id": 896, "sig_name": "EPS_CheckSum", "comment": "LKA_WarningType" }
        >>> dbc_class.UpdateDbcNetSigDiscription(sig_description,dbc_net)
        """

        for ecu in dbc_net["ecu_list"]:
            frame_list = [frame for frame in ecu["frame_list"] if ((frame["id"]) == (sig_description["id"])) ]
            if frame_list:
                frame = frame_list[0]
                sig_list = [
                    sig
                    for sig in frame["sig_list"]
                    if sig["name"] == sig_description["sig_name"]
                ]
                if sig_list:
                    sig_list[0]["sig_description"] = sig_description["comment"]
                    break
        else:
            print(str(sig_description) + "不存在与DBC NET中， 找不到对应的ID")
            logging.debug(str(sig_description) + "不存在与DBC NET中， 找不到对应的ID")
        pass  # UpdateDbcNetSigDiscription<<

    def SortDbcNet(self, dbc_net):
        """
        按名字重新排序 dbc_net
        """
        new_dbc_net = dict(dbc_net)

        def SorteDictListdByName(dict_list):
            return sorted(dict_list, key=lambda d: d["name"])

        # TODO SorteDictListdByName = lambda dict_list: sorted(dict_list, key = lambda d: d['name'])

        new_dbc_net["node_list"] = sorted(new_dbc_net["node_list"])
        new_dbc_net["ecu_list"] = SorteDictListdByName(new_dbc_net["ecu_list"])
        for tmp_ecu in new_dbc_net["ecu_list"]:
            tmp_ecu["frame_list"] = SorteDictListdByName(tmp_ecu["frame_list"])
            for tmp_frame in tmp_ecu["frame_list"]:
                tmp_frame["sig_list"] = SorteDictListdByName(tmp_frame["sig_list"])
        return new_dbc_net

    def Show_BusInfo(self, dbc_net):
        # dbc_net = self.dbc_net

        print("rate:", dbc_net["rate"])
        for tmp_ecu in dbc_net["ecu_list"]:
            print(tmp_ecu["name"], "\n")
            for tmp_frame in tmp_ecu["frame_list"]:
                print("  ", tmp_frame["name"], "\n")
                for tmp_sig in tmp_frame["sig_list"]:
                    print("    ", tmp_sig["name"], "\n")

    def GetSigClassListBySigNameList(self,sig_name_list = []):
        '''
            gcbb:2021-07-26 17:27:35
            按信号列表获取指定的信号类

        >>> import logging
        >>> logging.basicConfig(level=9)
        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> sig_class_list = dbc_class.GetSigClassListBySigNameList(["EPS_280.SAS_CalibrationSts"])
        >>> sig_class=sig_class_list[0];
        >>> print(sig_class.enum_value_list)
        ['Sensor_not_calibrated', 'Sensor_calibrated']
        >>> val = sig_class.GetVaueTableStrByVal(1.0);print(val)
        Sensor_calibrated
        '''
        sig_class_list = []
        
        for sig_name in sig_name_list:
            try:
                eval_str = "self."+sig_name
                tmp_class = eval(eval_str)
                # print(dir(tmp_class))
                sig_class_list.append(tmp_class)
            except Exception:
                logging.info(sig_name+"不在DBC中")
                pass
        return sig_class_list

    def GetInfoBySigName(self: "self", sig_name: "ECU_ID.sig 的格式"):

        tmp_info = sig_name.split(".")

        frame_name = tmp_info[0]

        tmp_frame_name = frame_name.split("_")
        ecu_name = tmp_frame_name[0]
        frame_id = tmp_frame_name[1]
        sig_name = tmp_info[1]

        frame_class = getattr(self, frame_name)
        sig_class = getattr(getattr(self, frame_name), sig_name)  # 获取信号对应的类
        if sig_class:
            res = {
                "ecu_name": ecu_name,
                "frame": frame_class,
                "frame_id": frame_id,
                "frame_name": frame_name,
                "sig_name": sig_name,
                "sig_class": sig_class,
            }
        else:
            print(sig_name, "不在DBC中，请检查信xls号配置表")
            err
        return res

    def Get_DbcNet(self):
        # new_dbc_net 和self.dbc_net 为同一地址
        new_dbc_net = self.dbc_net
        new_dbc_net["ecu_list"] = [
            ecu for ecu in new_dbc_net["ecu_list"] if (ecu["frame_list"])
        ]
        new_dbc_net["node_list"] = [ecu["name"] for ecu in new_dbc_net["ecu_list"]]
        return new_dbc_net

    def Set_DbcNet(self, dbc_net):
        self.CheckDbcNet(dbc_net)
        self.dbc_net = dbc_net

    def UpdateFrameList(self):
        dbc_net = self.Get_DbcNet()
        # 去除ECU 信息，给出frame list表
        for tmp_ecu in dbc_net["ecu_list"]:
            # for tmp_frame in tmp_ecu["frame_list"]:
            self.frame_list.extend(tmp_ecu["frame_list"])

    def ConvertFrameDataToNpArray(self,frame_data_list,timestamp_key = "Timestamp", data_key = "Data", Id_key = "ID"):
        '''
            2021-07-25 16:20:45
            接收can 报文列表，将can 报文数据拼接打包成list （使用时只需要加np.array即可）
            frame_data_list 是can报文 {"Timestamp","ID","Data"} 格式参考PythnCan
            传入的ID必须一致 #TODO 为完成
        >>> from dbc import Py_Dbc
        >>> dbc_class = Py_Dbc()
        >>> frame1 = {"Timestamp":1,"ID":896,"Data":[1,2,3,4,5,6,7,8]}
        >>> frame2 = {"Timestamp":2,"ID":896,"Data":[2,3,4,5,6,7,8,9]}
        >>> frame_data_list = [frame1,frame2]

        >>> frame_np_data = dbc_class.ConvertFrameDataToNpArray(frame_data_list)
        >>> print(frame_np_data)
        {'ID': 896, 'Timestamp': [[1], [2]], 'Data': [[1, 2, 3, 4, 5, 6, 7, 8], [2, 3, 4, 5, 6, 7, 8, 9]]}
        '''

        #TODO 检查ID是否都是一致的
        frame_data_nparray = {"ID":[],"Timestamp":[],"Data":[]}
        time_list = []
        frame_data_nparray[Id_key] = frame_data_list[0][Id_key]
        data8_list = []
        for frame in frame_data_list:
            # 将frame 的数据重新组织后赋给frame_data_nparray
            time_list.append([frame[timestamp_key]])
            data8_list.append(frame[data_key])

        frame_data_nparray["Timestamp"] = time_list# np.array(data8_list).transpose()
        frame_data_nparray["Data"] = data8_list# np.array(data8_list).transpose()
        return frame_data_nparray
    def UpdateFrameData(self, frame_array):
        """
        接收can 报文列表， 一次更新多帧报文
        报文ID可以不一致， 本函数会进行分组处理
        更新dbc的数据
        "data8":(0,1,2,3,4,5,6,7)# TODO2021-07-25 16:10:56 格式待定
        >>> from dbc import Py_Dbc
        >>> dbc_class = Py_Dbc("dbc/test.dbc")
        >>> frame = {"ID":640,"Timestamp":1,"Data":[255]*8}
        >>> dbc_class.UpdateFrameData([frame])
        >>> print(dbc_class.EPS_280.Data)
        [[255, 255, 255, 255, 255, 255, 255, 255]]
        >>> frame = {"ID":640,"Timestamp":2,"Data":[254]*8}
        >>> dbc_class.UpdateFrameData([frame])
        >>> print(dbc_class.EPS_280.Data)
        [[255, 255, 255, 255, 255, 255, 255, 255], [254, 254, 254, 254, 254, 254, 254, 254]]
        >>> frame = {"ID":641,"Timestamp":2,"Data":[254]*8}
        >>> dbc_class.UpdateFrameData([frame])
        >>> print(dbc_class.EPS_280.Data)
        [[255, 255, 255, 255, 255, 255, 255, 255], [254, 254, 254, 254, 254, 254, 254, 254]]
                """
        
        id_list = set([frame['ID'] for frame in frame_array])
        for _id in id_list:
            frame_class = self.GetFrameById(_id)
            if(frame_class):
                frame_array_by_id = [frame for frame in frame_array if frame["ID"]==_id]
                data8_array = [frame["Data"] for frame in frame_array_by_id]
                times_stamp_array =[frame["Timestamp"] for frame in frame_array_by_id]
                self.AddData(new_data = data8_array, timestamp= times_stamp_array)
                frame_class.UpdateSigData(frame_array =frame_array_by_id)

    def GetFrameList(self):
        return self.frame_list
        pass

    def GetFrameListByEcu(self, ecu_name):
        # 获取完整的帧信息
        frame_list = [
            frame for frame in self.frame_list if frame["send_ecu"] == ecu_name
        ]
        return frame_list
        pass

    def GetFrameNameListByEcu(self, ecu_name):
        frame_list = [
            frame["name"] for frame in self.frame_list if frame["send_ecu"] == ecu_name
        ]
        return frame_list
        pass

    def GetFrameById(self, can_id):
        '''
            从dbc_net 中查找到对应的can_id, 以后dbcnet 要改呀。。。。

        >>> import logging
        >>> logging.basicConfig(level=10)
        >>> dbc_class = Py_Dbc("dbc/C11.dbc")
        >>> frame_class =dbc_class.GetFrameById(0x280)
        '''
        # 通过CAN id 返回·frame句柄
        #TODO 以后<重写dbc_net>，此处需要重写
        frame={}
        for tmp_frame in self.frame_list:
            # logging.debug(str(tmp_frame["id"])+"--"+str(can_id)+str(tmp_frame["id"] == can_id))
            # logging.debug(str(type(tmp_frame["id"]))+"--"+str(type(can_id))+str(tmp_frame["id"] == can_id))

            if(tmp_frame["id"] == can_id):
                logging.debug("dbc中找到对应的ID"+hex(can_id))
                frame = tmp_frame
                break
        else:
            logging.debug("dbc中没有找到对应的ID"+hex(can_id))
            return None
        frame_class = getattr(self, frame["name"])
        return frame_class

    def GetSigValueBySigNameList(self,signal_name_list):
        '''
        2021-07-25 15:24:53
        依据信号名列表获取信号解析值
        {
            signal_name:信号的名称
            signal_value:信号的数值
            signale_value_text: 如果非枚举变量，则返回str的数值
            unit: 信号的单位，字符串 如果没有单位则返回NA字符串
        }
        >>> from dbc import Py_Dbc

        '''

    def GetSigNameList(self):
        # 打印dbc的所有信号 帧.信号 名 到文件
        sig_name_list = []
        for frame in self.GetFrameList():
            sig_name_list.extend(
                [frame["name"] + "." + sig["name"] for sig in frame["sig_list"]]
            )

        return sig_name_list  # END GetSigNameList

    def ExportDbcByNodeList(self, dbc_net, export_node_list):
        """
        从dbc_net 中导出export_node_list 相关的dbc
        """

        new_dbc_net = copy.deepcopy(dbc_net)
        for ecu in new_dbc_net["ecu_list"]:
            if ecu["name"] in list(export_node_list):
                # 如果发送ECU 在导出列表中， 则将发送ECU 全部导出
                print("导出ECU", ecu["name"])
                # 发送节点的信号完全导出，不论接收ECU是谁
                """
                for frame in ecu["frame_list"]:
                    for sig in frame["sig_list"]:
                        sig["recive_ecu"] = [
                            recive_ecu
                            for recive_ecu in sig["recive_ecu"]
                            if recive_ecu in export_node_list
                        ]
                        if not (sig["recive_ecu"]):
                            sig["recive_ecu"] = ["Vector__XXX"]
                """
                continue

            for frame in ecu["frame_list"]:
                if frame["send_ecu"] in export_node_list:
                    # 事实上因为前面的条件此处的frame 一定不是导出ECU发出来的这里永远到不了
                    err
                    continue
                else:
                    # 信号中接收节点与导出列表有重叠，则将信号留下
                    tmp_sig_list = frame["sig_list"]
                    frame["sig_list"] = [
                        sig
                        for sig in tmp_sig_list
                        if not (
                            self.CheckListIsStack(sig["recive_ecu"], export_node_list)
                        )
                    ]
                    # 删除信号接收列表中 不需要的接收节点
                    for sig in frame["sig_list"]:
                        sig["recive_ecu"] = [
                            recive_ecu
                            for recive_ecu in sig["recive_ecu"]
                            if recive_ecu in export_node_list
                        ]
            # 清理空的Frame
            ecu["frame_list"] = [
                frame for frame in ecu["frame_list"] if (frame["sig_list"])
            ]
        # 如果ECU 的发送节点都为空 则清理ECU
        new_dbc_net["ecu_list"] = [
            ecu for ecu in new_dbc_net["ecu_list"] if (ecu["frame_list"])
        ]
        new_dbc_net["node_list"] = [ecu["name"] for ecu in new_dbc_net["ecu_list"]]
        # 重新生成ECU NODE
        return new_dbc_net
        pass  # end ExportDbcByNodeList

    def CheckListIsStack(self, list1, list2):
        """
        判断元素是否有重叠
        """
        res = False
        list3 = list1[:]
        len1 = len(set(list1)) + len(set(list2))
        list3.extend(list2)
        len2 = len(set(list3))
        if len1 == len2:
            res = True
        return res

    def CheckDbcNet(self, dbc_net):
        for tmp_ecu in dbc_net["ecu_list"]:
            for tmp_frame in tmp_ecu["frame_list"]:
                bit_index = 0
                tmp_frame["sig_list"].sort(key=lambda x: x["bit_info"][0])
                for tmp_sig in tmp_frame["sig_list"]:
                    if tmp_sig["bit_info"][0] >= bit_index:
                        if tmp_sig["bit_info"][0] > bit_index:
                            print(
                                "warring:位信号有空缺失:",
                                tmp_frame["name"],
                                "->",
                                tmp_sig["name"],
                            )
                        bit_index = sum(tmp_sig["bit_info"])
                        pass
                    else:
                        print("位信号错误:", tmp_frame["name"], "->", tmp_sig["name"])
                        err
        pass

    def sort(self):
        bus = self.dbc_net

        bus["ecu_list"].sort(key=lambda x: x["name"])
        (ecu["frame_list"].sort(key=lambda x: x["id"]) for ecu in bus["ecu_list"])
        for ecu in bus["ecu_list"]:
            for frame in ecu["frame_list"]:
                (
                    sig_list.sort(key=lambda x: x["bit_info"][0])
                    for sig_list in frame["sig_list"]
                )
            pass

    def WriteMatlabEnumMFile(self):
        """
        遍历sig信号，获得所有枚举类型
        枚举名为 Enum_signame
        """
        enum_str = ""
        bus = self.dbc_net
        for ecu in bus["ecu_list"]:
            for frame in ecu["frame_list"]:
                for sig in frame["sig_list"]:
                    if sig["value_table"]['enum_value_list']:

                        enum_str += self.GenMfileEnumStr(
                            "Enum" + sig["name"], sig["value_table"]
                        )
            pass
        pass
        print(enum_str)
        return enum_str

    def GenMfileEnumStr(self, enum_name, table):
        enum_val_str = ", ".join(["'" + tmp_str + "'" for tmp_str in table['enum_value_list']])
        tmp_val_str = ",".join([str(val) for val in range(0, len(table))])
        tmp_str = (
            " if ~exist('"
            + enum_name
            + "','class')\n"
            + "Simulink.defineIntEnumType('"
            + enum_name
            + "', ...\n"
            + "{"
            + enum_val_str
            + "}, ...\n"
            + "["
            + tmp_val_str
            + "], ...\n"
            + "'DefaultValue', '"
            + table['enum_value_list'][0]
            + "', ...\n"
            + "'StorageType', 'uint8', ...\n"
            + "'AddClassNameToEnumNames', true);\n"
            + "end\n"
        )
        return tmp_str

    def ReplaceDbcSrt(self, src_str):
        # 替换str中的特殊字符
        return src_str.replace(u"\xa0", u"")
        pass

    def GenDbcHeader(self):
        dbc_str = """
VERSION ""
NS_ :
        NS_DESC_
        CM_
        BA_DEF_
        BA_
        VAL_
        CAT_DEF_
        CAT_
        FILTER
        BA_DEF_DEF_
        EV_DATA_
        ENVVAR_DATA_
        SGTYPE_
        SGTYPE_VAL_
        BA_DEF_SGTYPE_
        BA_SGTYPE_
        SIG_TYPE_REF_
        VAL_TABLE_
        SIG_GROUP_
        SIG_VALTYPE_
        SIGTYPE_VALTYPE_
        BO_TX_BU_
        BA_DEF_REL_
        BA_REL_
        BA_DEF_DEF_REL_
        BU_SG_REL_
        BU_EV_REL_
        BU_BO_REL_
        SG_MUL_VAL_

BS_:
"""

        dbc_str = self.ReplaceDbcSrt(dbc_str)
        return dbc_str

    def GenBuStr(self, dbc_net):
        res_str = "BU_: " + str.join(" ", dbc_net["node_list"]) + "\n\n\n"
        res_str = self.ReplaceDbcSrt(res_str)
        return res_str

    def GenDbcStr(self, dbc_net):
        """
        # dbc_str = {
                'head':''
                'sig':''  # 包含bo sg
                'CM_SG':'esc icu mcu'
                'BA_DEF_':'esc icu mcu'
                'BA_DEF_REL_':''
                'BA_DEF_DEF_':''
                'BA_DEF_DEF_REL':''
                'BA_':''
                'VAL_':''
        }
        """
        ba_def = """
BA_DEF_ SG_  "GenSigInactiveValue" INT 0 0;
BA_DEF_ SG_  "GenSigSendType" ENUM  "Cycle","OnChange","OnWrite";
BA_DEF_ SG_  "GenSigStartValue" INT 0 0;
BA_DEF_ SG_  "GenSigTimeoutValue" INT 0 1000000000;
BA_DEF_ BO_  "GenMsgCycleTime" INT 0 0;
BA_DEF_ BO_  "GenMsgCycleTimeActive" INT 0 0;
BA_DEF_ BO_  "GenMsgCycleTimeFast" INT 0 0;
BA_DEF_ BO_  "GenMsgDelayTime" INT 0 0;
BA_DEF_ BO_  "GenMsgILSupport" ENUM  "No","Yes";
BA_DEF_ BO_  "DiagRequest" ENUM  "No","Yes";
BA_DEF_ BO_  "DiagResponse" ENUM  "No","Yes";
BA_DEF_ BO_  "DiagState" ENUM  "No","Yes";
BA_DEF_ BO_  "GenMsgNrOfRepetition" INT 0 0;
BA_DEF_ BO_  "GenMsgSendType" ENUM  "Cycle","NoSendType","IfActive";
BA_DEF_ BO_  "GenMsgStartDelayTime" INT 0 65535;
BA_DEF_ BO_  "NmBaseAddress" INT 0 2047;
BA_DEF_ BO_  "NmMessage" ENUM  "No","Yes";
BA_DEF_ BU_  "CANoeStartDelay" INT 0 0;
BA_DEF_ BU_  "CANoeDrift" INT 0 0;
BA_DEF_ BU_  "CANoeJitterMin" INT 0 0;
BA_DEF_ BU_  "CANoeJitterMax" INT 0 0;
BA_DEF_ BU_  "ECU" STRING ;
BA_DEF_ BU_  "NodeLayerModules" STRING ;
BA_DEF_ BU_  "DiagStationAddress" HEX 0 15;
BA_DEF_ BU_  "ILUsed" ENUM  "No","Yes";
BA_DEF_ BU_  "NmCAN" INT 0 2;
BA_DEF_ BU_  "NmNode" ENUM  "Not","Yes";
BA_DEF_ BU_  "NmStationAddress" HEX 0 65535;
BA_DEF_  "BusType" STRING ;
BA_DEF_  "Manufacturer" STRING ;
BA_DEF_  "NmMessageCount" INT 0 255;
BA_DEF_  "NmType" STRING ;
"""

        ba_def_def = """
BA_DEF_DEF_  "GenSigInactiveValue" 0;
BA_DEF_DEF_  "GenSigSendType" "Cycle";
BA_DEF_DEF_  "GenSigStartValue" 0;
BA_DEF_DEF_  "GenSigTimeoutValue" 0;
BA_DEF_DEF_  "GenMsgCycleTime" 0;
BA_DEF_DEF_  "GenMsgCycleTimeActive" 0;
BA_DEF_DEF_  "GenMsgCycleTimeFast" 0;
BA_DEF_DEF_  "GenMsgDelayTime" 0;
BA_DEF_DEF_  "GenMsgILSupport" "No";
BA_DEF_DEF_  "DiagRequest" "No";
BA_DEF_DEF_  "DiagResponse" "No";
BA_DEF_DEF_  "DiagState" "No";
BA_DEF_DEF_  "GenMsgNrOfRepetition" 0;
BA_DEF_DEF_  "GenMsgSendType" "Cycle";
BA_DEF_DEF_  "GenMsgStartDelayTime" 0;
BA_DEF_DEF_  "NmBaseAddress" 1024;
BA_DEF_DEF_  "NmMessage" "No";
BA_DEF_DEF_  "CANoeStartDelay" 0;
BA_DEF_DEF_  "CANoeDrift" 0;
BA_DEF_DEF_  "CANoeJitterMin" 0;
BA_DEF_DEF_  "CANoeJitterMax" 0;
BA_DEF_DEF_  "ECU" "";
BA_DEF_DEF_  "NodeLayerModules" "";
BA_DEF_DEF_  "DiagStationAddress" 0;
BA_DEF_DEF_  "ILUsed" "No";
BA_DEF_DEF_  "NmCAN" 0;
BA_DEF_DEF_  "NmNode" "Not";
BA_DEF_DEF_  "NmStationAddress" 0;
BA_DEF_DEF_  "BusType" "CAN";
BA_DEF_DEF_  "Manufacturer" "";
BA_DEF_DEF_  "NmMessageCount" 128;
BA_DEF_DEF_  "NmType" "";
"""
        frame_str = self.GenFrame(dbc_net)

        ba_str = frame_str["BA_"]
        # rate
        dbc_info = {
            "head": self.GenDbcHeader(),
            "BU_": self.GenBuStr(dbc_net),
            "BO_": frame_str["BO_"],
            "CM_":frame_str["CM_"],
            "BA_DEF_": ba_def,
            "BA_DEF_REL_": "",
            "BA_DEF_DEF_": ba_def_def,
            "BA_DEF_DEF_REL": "",
            "BA_": ba_str,
            "VAL_": frame_str["VAL_"],
        }

        self.GenDbcRateStrFromDbcNet(dbc_info, dbc_net)
        self.GenDbcNetNameStrFromDbcNet(dbc_info, dbc_net)
        dbc_str = ""
        for key in dbc_info.keys():
            dbc_str += dbc_info[key]
        return dbc_str
        pass

    def WriteDbcNetToFile(self, dbc_net, dbc_file):
        dbc_str = self.GenDbcStr(dbc_net)
        file_object = open(dbc_file, "w+", encoding="gbk")  # self.file_name[0]
        file_object.write(dbc_str)
        file_object.close()

    def GenDbcRateStrFromDbcNet(self, dbc_info, dbc_net):
        dbc_info["BA_DEF_"] += 'BA_DEF_  "Baudrate" INT 0 1000000;\n'
        dbc_info["BA_DEF_DEF_"] += (
            'BA_DEF_DEF_  "Baudrate" ' + str(dbc_net["rate"]) + ";\n"
        )
        dbc_info["BA_"] += 'BA_ "Baudrate" ' + str(dbc_net["rate"]) + ";\n"
        pass

    def GenDbcNetNameStrFromDbcNet(self, dbc_info, dbc_net):
        dbc_info["BA_DEF_"] += 'BA_DEF_  "DBName" STRING;\n'
        dbc_info["BA_DEF_DEF_"] += 'BA_DEF_DEF_  "DBName" "";\n'
        dbc_info["BA_"] += 'BA_ "DBName" "' + dbc_net["name"] + '";\n'
        pass

    #返回帧相关信息
    '''
            res_str=
            {
                "frame":head_str,
                "cm_str":cm_str,
                "ba_cyc_time":ba_cyc_time,
                "val_str":val_str,
            }
    '''
    def GenFrame(self, dbc_net):
        bo_str = ''
        cm_str =''
        val_str = ''
        ba_def_str = ''
        ba_str=''
        # print(dbc_net,'\n')
        for ecu in dbc_net['ecu_list']:
            for frame in ecu['frame_list']:
                bo_str += 'BO_ '
                ba_str += 'BA_ "GenMsgCycleTime" BO_ '

                bo_str += (
                    str(frame['id'])
                    + ' ' + frame['name'] 
                    + ': ' + str(frame['data_len']) 
                    + ' ' + ecu['name'] + '\n')
                ba_str += ( str(frame['id'])+' ' + str(frame['cycle']) + ';\n')

                for sig in frame['sig_list']:
                    logging.info("生成信号:"+str(sig))
                    bo_str += (
                          ' SG_ ' + sig['name']
                        + ' : ' + str(sig['bit_info'][0]) 
                        + '|' + str(sig['bit_info'][1])
                        + '@1+ (' + str(sig['cal_info'][0]) + ',' + str(sig['cal_info'][1]) + ')'
                        + ' [' + str(sig['min_max'][0]) + '|' + str(sig['min_max'][1]) + '] '
                        + '"' + sig['unit'] +'" ' 
                        + str.join(',', sig['recive_ecu'])
                        + '\n')

                    cm_str +=( 'CM_ SG_ ' + str(frame['id']) + ' ' + sig['name'] + ' "' + sig['sig_description'] + '";\n')

                    # print(sig['value_table']['table_name'])
                    if(sig['value_table']['table_name'] == 'none'):
                        ba_def_str +=(
                            'BA_DEF_ SG_  "' + sig['name'] +'" FLOAT '+ str(sig['min_max'][0]) + ' ' + str(sig['min_max'][1]) +';\n'
                        )
                    else:
                        ba_def_str +=(
                            'BA_DEF_ SG_  "' + sig['name'] +'" ENUM '+ str.join(',',['"'+i+'"' for i in sig['value_table']['enum_value_list']]) + ';\n'
                        )

                        val_str +=(
                            'VAL_ '+ str(frame['id']) +' ' +
                            sig['name'] +' ' +
                            str.join(' ',
                                 [(str(i)+' "' + sig['value_table']['enum_value_list'][i])+'"' 
                                  for i in reversed(range(len(sig['value_table']['enum_value_list'])))]) +
                            ';\n')

        res_str= {
            "BA_DEF_":ba_def_str,
            "BO_":self.ReplaceDbcSrt(bo_str),
            "CM_":self.ReplaceDbcSrt(cm_str),
            "BA_":self.ReplaceDbcSrt(ba_str),
            "VAL_":self.ReplaceDbcSrt(val_str),
        }
        return res_str
    def GetSigValListByTime(self, sig_name, time, t_gate):
        # TODO GAte
        # TODO 优化取数据的算法，可以大幅节约时间
        tmp_info = self.GetInfoBySigName(sig_name)
        frame = getattr(self, tmp_info["frame_name"])
        sig = getattr(frame, tmp_info["sig_name"])

        # print("msg20201209202552", frame.Timestamp, time, t_gate)
        pos = frame.GetTPos(time, t_gate)

        res_sig_val = {"Data": [], "Timestamp": []}

        if len(pos) > 0:
            res_sig_val["Data"] = sig.Data[pos]
            res_sig_val["Timestamp"] = frame.Timestamp[0][pos]
        return res_sig_val

if __name__ == "__main__":

    import doctest
    doctest.testmod()
    import unittest
    import parameterized
    import os
    import time
    import re

    from multiprocessing import Manager as Mgr
    from multiprocessing import Queue

    formatter = ("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    logging.basicConfig(level=logging.DEBUG, format =formatter)

    '''测试'''
    dbc0_name = 'dbc0.dbc'

    dadbcta = [
        # [dbc0_name],
        ['D:/gcbb/python/DBC_XLSCOVERT/C11.dbc']
    ]
    dbc_name_list = [
        # ['dbc/附件1-导出EPS+ESCi无RX.dbc'],
        ['C11.dbc'],
        ['附件2-事件型报文.dbc'],
    ]
    class test(unittest.TestCase):
        '''
        测试 dbc
        '''
        # @parameterized.parameterized.expand(data)
        def test_0parise_sig_description(self):
            dbc_name = dbc0_name
            '''
                测试加载DBC
            '''
            dbc_class = Py_Dbc()
            dbc_class.load_dbc('dbc/'+dbc_name)
            dbc_net = dbc_class.Get_DbcNet()

            cm_sg_str = 'CM_ SG_ 291 ABS_CheckSum "COMMENT";'
            res_tag = {
                'id' : '291',
                'sig_name' : 'ABS_CheckSum',
                'comment' : 'COMMENT'
            }

            sig_description = dbc_class.PariseSigDiscription(cm_sg_str)
            self.assertEqual(sig_description['comment'], "COMMENT", "信号说明解析错误")
            dbc_class.UpdateDbcNetSigDiscription(sig_description, dbc_net)
            sig = None

            for ecu in dbc_net['ecu_list']:
                frame = [(frame) for frame in ecu['frame_list'] if frame['id'] == sig_description['id'] ][0]
                if(frame):

                    sig_list = [sig for sig in frame['sig_list'] if sig['name'] == sig_description['sig_name']]
                    if(sig_list):
                        sig = sig_list[0]
            # self.assertEqual(sig['sig_description'], "COMMENT", '网表信号说明解析错误')
            self.assertEqual(sig['sig_description'], "COMMENT", 'dbc net is err')
            # self.assertEqual(GetFrameById(291), "COMMENT", "信号说明解析错误")

        @parameterized.parameterized.expand(dbc_name_list)
        def test_1(self,dbc_name):
            '''
                导出DBC
            '''

            work_path =  './'
            dbc_full_path_name = work_path +'dbc/'+ dbc_name
            dbc_class = Py_Dbc()
            dbc_class.load_dbc(dbc_full_path_name)
            # dbc_net_str = dbc_class.Get_DbcNet()
            #测试导出DBC
            new_net = dbc_class.ExportDbcByNodeList(dbc_class.dbc_net, ['EPS'])
            dbc_class.WriteDbcNetToFile(new_net, work_path + '/dbc/exp_' + dbc_name)
    unittest.main()

    pass
